#ifndef _UTILEX_SEMTHREAD_HPP_
#define _UTILEX_SEMTHREAD_HPP_

#include <crt_util.h>
#include <utilex/sem.hpp>

#ifdef __cplusplus

class CSemThread
{
public:
    CSemThread()
    {
        m_Exit = 0;
        thread = INVALID_HANDLE_VALUE;
    }
    virtual ~CSemThread() { }

public:
    static void sem_thread_proc(void* pthis)
    {
        CSemThread* p = static_cast<CSemThread*>(pthis);
        if (p) {
            p->Post();
            p->Sem_Thread_Run_Proc();
        }
    }

    int PostSem()
    {
        rc_error(thread != INVALID_HANDLE_VALUE, S_ERROR);
        m_SemPost.Post();
        return S_SUCCESS;
    }

    int Start_Thread()
    {
        rc_error(thread == INVALID_HANDLE_VALUE, S_ERROR);
        int rc = _thread_create(&thread, CSemThread::sem_thread_proc, this);
        rc_error(rc == S_SUCCESS, S_ERROR);
        this->Wait();
        return S_SUCCESS;
    }

    int Stop_Thread()
    {
        rc_error(thread != INVALID_HANDLE_VALUE, S_ERROR);

        Exit_Thread();
        this->m_SemPost.Post();
        _thread_join(&thread);
        return S_SUCCESS;
    }

protected:
    std_method(Sem_Thread_Run_Proc)()
    {
        while (!m_Exit) {
            this->m_SemPost.Wait();
            rc_error_break(m_Exit == 0);
            this->Sem_Thread_Run();
        }
        return S_OK;
    }

private:
    int Post()
    {
        rc_error(thread != INVALID_HANDLE_VALUE, S_ERROR);
        m_Sem.Post();
        return S_SUCCESS;
    }
    int Wait()
    {
        rc_error(thread != INVALID_HANDLE_VALUE, S_ERROR);
        m_Sem.Wait();
        return S_SUCCESS;
    }
    HRESULT Exit_Thread()
    {
        SYNC_OBJ(&m_csLock);
        m_Exit = 1;
        return S_OK;
    }

public:
    std_method(Sem_Thread_Run)() PURE;

protected:
    _thread_t thread;
    CAutoLock m_csLock;
    CSemHandle m_SemPost;
    CSemHandle m_Sem;
    UINT m_Exit;
};

#endif

#endif
